/******************************************************************************中
 * @brief: eth task
 * @Author: aple
 * @Date: 2022-12-14 12:37:50
 * @LastEditors: aple
 * @LastEditTime: 2022-12-14 12:41:45
 * @Verision: 1.0.0.0
 ******************************************************************************/
#include "framework.h"
#include "eth_task.h"
#include "server/tcp_server_app.h"

/*****************************************************************************
 * @brief   const
 *****************************************************************************/

/*****************************************************************************
 * @brief   function
 *****************************************************************************/
int TCP_ServerHandle(void);
void TCP_ServerThread(void const *argument);

/*****************************************************************************
 * @brief   Global var
 *****************************************************************************/

/*****************************************************************************
 * @brief   loacal var
 *****************************************************************************/

/*****************************************************************************
 * @brief   task var
 *****************************************************************************/
osThreadDef(TCP_ServerThread, osPriorityNormal, 1, 0x1000);
void eth_app_server_init(void)
{
	os_obj.tid_eth = osThreadCreate(osThread(TCP_ServerThread), NULL);
}

void eth_app_server_deinit(void)
{
}

/*******************************************************************************
 * @brief: server thread
 * @param void
 * @return {*}
 ******************************************************************************/
void TCP_ServerThread(void const *argument)
{
	while (1)
	{
		TCP_ServerHandle();
	}
}

/*******************************************************************************
 * @brief: server app data
 ******************************************************************************/
int_t server_fd, client_fd = 0;
SOCKADDR_IN serverAddr;
SOCKADDR_IN clientAddr;
char ip_address[16];
socket_port_t m_socketfd;

static void client_handle(uint32_t socket_port);

/*******************************************************************************
 * @brief: server thread
 * @param void
 * @return {*}
 ******************************************************************************/
int TCP_ServerHandle(void)
{
	int ret;

	// 创建 socket
	server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (server_fd < 0)
	{
		return SOCKET_ERROR;
	}

	// 绑定socket和端口号
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	serverAddr.sin_port = htons(APP_SERVER_PORT);
	serverAddr.sin_family = AF_INET;

	if (bind(server_fd, (SOCKADDR *)&serverAddr, sizeof(SOCKADDR_IN)) < 0)
	{
		closesocket(server_fd);
		return 0;
	}

	// 启动监听
	if (listen(server_fd, 5) < 0)
	{
		closesocket(server_fd);
		return 0;
	}

	fd_set fdRead;
	TIMEVAL m_TimeVal;
	m_TimeVal.tv_sec = 0;
	m_TimeVal.tv_usec = 0;

	// 扫描连接
	while (1)
	{
		FD_ZERO(&fdRead);
		FD_SET(server_fd, &fdRead);

		ret = select(0, &fdRead, NULL, NULL, &m_TimeVal);

		if (ret == SOCKET_ERROR)
		{
			ret = 0;
			break;
		}

		// 检测到有客户端连接本服务器
		if (ret > 0)
		{
			if (FD_ISSET(server_fd, &fdRead))
			{
				int len = sizeof(SOCKADDR_IN);

				// 获取已连接客户端
				client_fd = accept(server_fd, (SOCKADDR *)&clientAddr, &len);
				if (IsValidFD(client_fd))
				{
					strcpy(ip_address, inet_ntoa(clientAddr.sin_addr));
					m_socketfd.fd = client_fd;

					// 处理已连接的客户端链接
					client_handle((uint32_t)&m_socketfd);

					// 关闭链接
					closesocket(client_fd);
					if (strlen(ip_address) == 0 || strcmp(ip_address, "0.0.0.0") == 0)
					{
						if (client_fd > 0)
						{
							closesocket(client_fd);
							client_fd = SOCKET_ERROR;
						}
						continue;
					}
				}
				else
				{
					continue;
				}
			}
		}

		osDelay(1);
	}

	return ret;
}

/*******************************************************************************
 * @brief: client handle
 * @param socket_port socket
 * @return {*}
 ******************************************************************************/
static void client_handle(uint32_t socket_port)
{
	socket_port_t *m_socket_port = (socket_port_t *)socket_port;
	int clientFd = m_socket_port->fd;
	fd_set readfds;

	// 接收数据缓存
	uint8_t *RecvBuf = malloc(nKB(4));

	// 扫描接收数据
	while (1)
	{
		FD_ZERO(&readfds);
		FD_SET(clientFd, &readfds);

		// 读取接收的数据并回显
		if (FD_ISSET(clientFd, &readfds))
		{
			int RecvLen = recv(clientFd, RecvBuf, nKB(4), 0);

			if (RecvLen <= 0)
			{
				break;
			}

			int SendLen = send(clientFd, RecvBuf, RecvLen, 0);
			if (SendLen <= 0)
			{
				break;
			}
		}

		osDelay(1);
	}

	free(RecvBuf);
}

/*******************************************************************************
 * @brief: TcpApp config default
 ******************************************************************************/
error_t etcp_TcpAppServerOpenCallback(TcpAppClientConnection *connection, IpAddr clientIpAddr, uint16_t clientPort);
void etcp_TcpAppServerCloseCallback(TcpAppClientConnection *connection);
void etcp_TcpAppServerLockCallback(TcpAppClientConnection *connection);
void etcp_TcpAppServerUnlockCallback(TcpAppClientConnection *connection);
error_t etcp_TcpAppServerProcessAduCallback(
    TcpAppClientConnection *connection,
    const uint8_t *request, size_t requestLen, uint8_t *response,
    size_t *responseLen);
void etcp_TcpAppServerTickCallback(TcpAppServerContext *context);

const TcpAppServerSettings etcp_server_cfg_default = {
    .openCallback = etcp_TcpAppServerOpenCallback,
    .closeCallback = etcp_TcpAppServerCloseCallback,
    .lockCallback = etcp_TcpAppServerLockCallback,
    .unlockCallback = etcp_TcpAppServerUnlockCallback,
    .processAduCallback = etcp_TcpAppServerProcessAduCallback, // 用于调试数据包
    .tickCallback = etcp_TcpAppServerTickCallback,
};

/*******************************************************************************
 * @brief: var
 ******************************************************************************/
TcpAppServerContext etcp_server_context;

/*******************************************************************************
 * @brief: eth TcpApp init
 * @param void
 * @return {*}
 ******************************************************************************/
void etcp_server_init(void)
{
    TcpAppServerSettings etcp_cfg;

    memcpy(&etcp_cfg, &etcp_server_cfg_default, sizeof(etcp_cfg));

    etcp_cfg.task.priority = osPriorityNormal;
    etcp_cfg.task.stackSize = TCP_APP_SERVER_STACK_SIZE;
    etcp_cfg.interface = &netInterface[0];
    etcp_cfg.port = TCP_APP_TCP_SERVER_PORT;
    etcp_cfg.timeout = TCP_APP_SERVER_TIMEOUT;

    TcpAppServerInit(&etcp_server_context, &etcp_cfg);

    TcpAppServerStart(&etcp_server_context);
}

/*******************************************************************************
 * @brief: eth TcpApp deinit
 * @param void
 * @return {*}
 ******************************************************************************/
void etcp_server_deinit(void)
{
    TcpAppServerStop(&etcp_server_context);
    TcpAppServerDeinit(&etcp_server_context);
	// 需手动删除OS任务和OS事件
	osDeleteEvent(&etcp_server_context.event);
	osDeleteTask(etcp_server_context.taskId);
}

/**
 * @brief TCP connection open callback function
 **/

error_t etcp_TcpAppServerOpenCallback(TcpAppClientConnection *connection, IpAddr clientIpAddr, uint16_t clientPort)
{
    return 0;
}

/**
 * @brief TCP connection close callback function
 **/
void etcp_TcpAppServerCloseCallback(TcpAppClientConnection *connection)
{
}

/**
 * @brief Lock TcpApp table callback function
 **/

void etcp_TcpAppServerLockCallback(TcpAppClientConnection *connection)
{
}

/**
 * @brief Unlock TcpApp table callback function
 **/

void etcp_TcpAppServerUnlockCallback(TcpAppClientConnection *connection)
{
}

/**
 * @brief PDU processing callback function
 **/
error_t etcp_TcpAppServerProcessAduCallback(
    TcpAppClientConnection *connection,
    const uint8_t *request, size_t requestLen, uint8_t *response,
    size_t *responseLen)
{
	// responseLen 不能大于 TCP_APP_MAX_ADU_SIZE
	strcpy((char*)response, "resp: ");
	rang_limit_high(requestLen, TCP_APP_TCP_SERVER_MAX_ADU_SIZE - 20);
	memcpy(&response[6], request, requestLen);
	response[requestLen+6] = '\n';
	
    *responseLen = requestLen + 7;
	
    return 0;
}

/**
 * @brief Tick callback function
 **/

void etcp_TcpAppServerTickCallback(TcpAppServerContext *context)
{
}
